solve mass continuity of reservoir using runge kutta method
References:
Chow, V. T., Maidment, D. R. &Mays, L. W. (1988) Applied Hydrology. McGraw-Hill, New York, USA
Fenton, J.D. (1992) Reservoir routing, Hydrological Sciences Journal, 37(3), 233-246, DOI: 10.1080/02626669209492584
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=float), | intent(in) | :: | hini |
initial stage value (m) |
||
real(kind=float), | intent(in) | :: | Qin_begin |
input discharge at the beginning of time step (m3/s) |
||
real(kind=float), | intent(in) | :: | Qin_end |
input discharge at the end of time step (m3/s) |
||
integer, | intent(in) | :: | dt |
time step (s) |
||
type(Table), | intent(in) | :: | geometry |
geometry of reservoir |
||
integer, | intent(in) | :: | rk |
solution order 3 or 4 |
||
integer, | intent(in) | :: | typOut |
type ofoutflow: 1=free flow 2=target level |
||
real(kind=float), | intent(in) | :: | hTarget |
follow a target (observed) stage (m) |
||
real(kind=float), | intent(in) | :: | eFlow |
environmental flow (m3/s) |
||
real(kind=float), | intent(in) | :: | freeFlow |
free flow (m3/s) |
||
real(kind=float), | intent(in) | :: | freeFlowElevation |
free flow elevation (m asl) |
||
character(len=3), | intent(in) | :: | QoutDOY |
doy to compute Qout |
Type | Visibility | Attributes | Name | Initial | |||
---|---|---|---|---|---|---|---|
real(kind=float), | public | :: | Q1third | ||||
real(kind=float), | public | :: | Q2third | ||||
real(kind=float), | public | :: | Qout | ||||
real(kind=float), | public | :: | area | ||||
real(kind=float), | public | :: | dh | ||||
real(kind=float), | public | :: | dh1 | ||||
real(kind=float), | public | :: | dh2 | ||||
real(kind=float), | public | :: | dh3 | ||||
real(kind=float), | public | :: | dh4 | ||||
real(kind=float), | public | :: | h1 | ||||
real(kind=float), | public | :: | h2 | ||||
real(kind=float), | public | :: | h3 |
FUNCTION RungeKutta & ( hini, Qin_begin, Qin_end, dt, geometry, rk, typOut, hTarget, & eFlow, freeFlow, freeFlowElevation, QoutDOY ) & RESULT (stage) IMPLICIT NONE ! Function arguments ! Arguments with intent(in): REAL (KIND = float), INTENT(IN) :: hini !!initial stage value (m) REAL (KIND = float), INTENT(IN) :: Qin_begin !!input discharge at the beginning of time step (m3/s) REAL (KIND = float), INTENT(IN) :: Qin_end !!input discharge at the end of time step (m3/s) INTEGER, INTENT(IN) :: dt !!time step (s) TYPE (Table), INTENT(IN) :: geometry !!geometry of reservoir INTEGER, INTENT(IN) :: rk !! solution order 3 or 4 INTEGER, INTENT(IN) :: typOut !!type ofoutflow: 1=free flow 2=target level REAL (KIND = float), INTENT(IN) :: hTarget !!follow a target (observed) stage (m) REAL (KIND = float), INTENT(IN) :: eFlow !!environmental flow (m3/s) REAL (KIND = float), INTENT(IN) :: freeFlow !! free flow (m3/s) REAL (KIND = float), INTENT(IN) :: freeFlowElevation !! free flow elevation (m asl) CHARACTER (LEN = 3), INTENT(IN) :: QoutDOY !!doy to compute Qout ! Arguments with intent(OUT): REAL (KIND = float) :: stage !local declaration: REAL(KIND = float) :: h1, h2 REAL(KIND = float) :: h3 !used only if rk = 4 REAL(KIND = float) :: dh1, dh2, dh3 REAL(KIND = float) :: dh4 !used only if rk = 4 REAL(KIND = float) :: dh REAL(KIND = float) :: Q1third, Q2third REAL(KIND = float) :: Qout REAL(KIND = float) :: area !(m2) !------------end of declaration------------------------------------------------ SELECT CASE (rk) CASE(3) IF ( typOut == 2 .AND. hini < hTarget) THEN Qout = MIN (eFlow, Qin_begin) !step 1 !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh1 dh1 = (Qin_begin - Qout) * dt / area !update h1 h1 = hini + dh1 / 3.0 !step 2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh2 dh2 = (Q1third - Qout) * dt / area !update h2 h2 = hini + 2.0 * dh2 / 3.0 !step 3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh3 dh3 = (Q2third - Qout) * dt / area ELSE !step 1 !find Qout IF ( hini <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) IF ( eFlow > 0.) THEN Qout = MAX (eFlow, Qout) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh1 dh1 = (Qin_begin - Qout) * dt / area !update h1 h1 = hini + dh1 / 3.0 !step2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) !find Qout IF ( h1 <= freeFlowElevation .AND. Q1third < freeFlow ) THEN Qout = Q1third ELSE CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh2 dh2 = (Q1third - Qout) * dt / area !update h2 h2 = hini + 2.0 * dh2 / 3.0 !step3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) !find Qout IF ( h2 <= freeFlowElevation .AND. Q2third < freeFlow ) THEN Qout = Q2third ELSE CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh3 dh3 = (Q2third - Qout) * dt / area END IF dh = dh1 / 4.0 + 3.0 * dh3 / 4.0 CASE(4) !IF ( typOut == 2 .AND. hini < hTarget) THEN ! ! Qout = MIN (eFlow, Qin_begin) ! ! !step 1 ! !find area in table geometry ! CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & ! keyOut='area', match='linear', & ! valueOut=area, bound = 'extendlinear' ) ! ! !compute dh1 ! dh1 = (Qin_begin - Qout) * area ! !write(*,*) dh1, Qout, eflow, Qin_begin, hini, htarget ! ! !update h1 ! h1 = hini + dh1 / 3.0 ! ! !step 2 ! Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) ! ! !find area in table geometry ! CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & ! keyOut='area', match='linear', & ! valueOut=area, bound = 'extendlinear' ) ! ! !compute dh2 ! dh2 = (Q1third - Qout) * dt / area ! ! !update h2 ! h2 = hini - 1.0 / 3.0 * dh1 + dh2 ! ! !step 3 ! Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) ! ! !find area in table geometry ! CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & ! keyOut='area', match='linear', & ! valueOut=area, bound = 'extendlinear' ) ! ! !compute dh3 ! dh3 = (Q2third - Qout) * dt / area ! ! !update h3 ! h3 = hini + dh1 - dh2 + dh3 ! ! !step4 ! !find area in table geometry ! CALL TableGetValue ( valueIn = h3, tab = geometry, keyIn = 'h', & ! keyOut='area', match='linear', & ! valueOut=area, bound = 'extendlinear' ) ! ! !compute dh4 ! dh4 = (Qin_end - Qout) * dt / area ! !ELSE !step 1 !find Qout IF ( typOut == 2 .AND. hini < hTarget) THEN Qout = MIN (eFlow, Qin_begin) ELSE IF ( typOut == 2 .AND. hini >= hTarget) THEN CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) IF ( eFlow > 0. ) THEN Qout = MAX (eFlow, Qout) END IF ELSE IF ( hini <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh1 dh1 = (Qin_begin - Qout) * dt / area !update h1 h1 = hini + dh1 / 3.0 !step2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) IF ( typOut == 1 ) THEN !update Qout IF ( h1 <= freeFlowElevation .AND. Q1third < freeFlow ) THEN Qout = Q1third ELSE CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh2 dh2 = (Q1third - Qout) * dt / area !update h2 h2 = hini - 1.0 / 3.0 * dh1 + dh2 !step3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) IF ( typOut == 1 ) THEN !update Qout IF ( h2 <= freeFlowElevation .AND. Q2third < freeFlow ) THEN Qout = Q2third ELSE CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh3 dh3 = (Q2third - Qout) * dt / area !update h3 h3 = hini + dh1 - dh2 + dh3 !step 4 IF ( typOut == 1 ) THEN !update Qout IF ( h3 <= freeFlowElevation .AND. Qin_end < freeFlow ) THEN Qout = Qin_end ELSE CALL TableGetValue ( valueIn = h3, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h3, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh4 dh4 = (Qin_end - Qout) * dt / area !END IF dh = dh1 / 8.0 + 3.0 * dh2 / 8.0 + 3.0 * dh3 / 8.0 + dh4 / 8.0 CASE DEFAULT CALL Catch ('error', 'RungeKutta', 'order Runge-Kutta not valid: ', & argument = ToString(rk)) STOP END SELECT !update reservoir stage stage = hini + dh RETURN END FUNCTION RungeKutta